/**
 * 用户体验优化工具库
 * 包含Loading状态、错误提示、Toast通知等功能
 */

class UXUtils {
    constructor() {
        this.loadingStates = new Map();
        this.toastContainer = null;
        this.modalContainer = null;
        this.confirmDialog = null;
        this.init();
    }

    /**
     * 初始化UX组件
     */
    init() {
        this.createToastContainer();
        this.createModalContainer();
        this.createConfirmDialog();
        this.setupGlobalErrorHandling();
        this.setupAjaxInterceptors();
    }

    /**
     * 创建Toast通知容器
     */
    createToastContainer() {
        if (document.getElementById('toast-container')) return;
        
        const container = document.createElement('div');
        container.id = 'toast-container';
        container.className = 'fixed top-4 right-4 z-50 space-y-2';
        document.body.appendChild(container);
        this.toastContainer = container;
    }

    /**
     * 创建模态框容器
     */
    createModalContainer() {
        if (document.getElementById('modal-container')) return;
        
        const container = document.createElement('div');
        container.id = 'modal-container';
        container.className = 'fixed inset-0 z-50 hidden';
        document.body.appendChild(container);
        this.modalContainer = container;
    }

    /**
     * 创建确认对话框
     */
    createConfirmDialog() {
        if (document.getElementById('confirm-dialog')) return;
        
        const dialog = document.createElement('div');
        dialog.id = 'confirm-dialog';
        dialog.className = 'fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center z-50';
        dialog.innerHTML = `
            <div class="bg-white rounded-lg p-6 max-w-md w-full mx-4">
                <h3 class="text-lg font-semibold mb-4" id="confirm-title">确认操作</h3>
                <p class="text-gray-600 mb-6" id="confirm-message">确定要执行此操作吗？</p>
                <div class="flex justify-end space-x-3">
                    <button id="confirm-cancel" class="px-4 py-2 text-gray-600 bg-gray-200 rounded hover:bg-gray-300 transition-colors">
                        取消
                    </button>
                    <button id="confirm-ok" class="px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700 transition-colors">
                        确定
                    </button>
                </div>
            </div>
        `;
        document.body.appendChild(dialog);
        this.confirmDialog = dialog;
    }

    /**
     * 显示Toast通知
     * @param {string} message - 通知消息
     * @param {string} type - 通知类型 (success, error, warning, info)
     * @param {number} duration - 显示时长（毫秒）
     */
    showToast(message, type = 'info', duration = 3000) {
        const toast = document.createElement('div');
        const icons = {
            success: '✓',
            error: '✗',
            warning: '⚠',
            info: 'ℹ'
        };
        
        const colors = {
            success: 'bg-green-500',
            error: 'bg-red-500',
            warning: 'bg-yellow-500',
            info: 'bg-blue-500'
        };

        toast.className = `${colors[type]} text-white px-6 py-4 rounded-lg shadow-lg flex items-center space-x-3 min-w-[300px] transform transition-all duration-300 translate-x-full opacity-0`;
        toast.innerHTML = `
            <span class="text-xl font-bold">${icons[type]}</span>
            <span class="flex-1">${message}</span>
            <button class="ml-4 text-white hover:text-gray-200" onclick="this.parentElement.remove()">×</button>
        `;

        this.toastContainer.appendChild(toast);

        // 触发动画
        setTimeout(() => {
            toast.classList.remove('translate-x-full', 'opacity-0');
        }, 10);

        // 自动移除
        setTimeout(() => {
            toast.classList.add('translate-x-full', 'opacity-0');
            setTimeout(() => toast.remove(), 300);
        }, duration);
    }

    /**
     * 显示成功通知
     */
    showSuccess(message, duration) {
        this.showToast(message, 'success', duration);
    }

    /**
     * 显示错误通知
     */
    showError(message, duration) {
        this.showToast(message, 'error', duration || 5000);
    }

    /**
     * 显示警告通知
     */
    showWarning(message, duration) {
        this.showToast(message, 'warning', duration);
    }

    /**
     * 显示信息通知
     */
    showInfo(message, duration) {
        this.showToast(message, 'info', duration);
    }

    /**
     * 显示Loading状态
     * @param {string} key - Loading状态的唯一标识
     * @param {string} message - Loading消息
     * @param {HTMLElement} target - 目标元素（可选）
     */
    showLoading(key, message = '加载中...', target = null) {
        if (this.loadingStates.has(key)) {
            this.updateLoadingMessage(key, message);
            return;
        }

        const loadingElement = document.createElement('div');
        loadingElement.className = 'fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50';
        loadingElement.id = `loading-${key}`;
        loadingElement.innerHTML = `
            <div class="bg-white rounded-lg p-6 flex flex-col items-center space-y-4">
                <div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
                <p class="text-gray-700 font-medium">${message}</p>
            </div>
        `;

        // 如果指定了目标元素，在目标元素内显示loading
        if (target && target !== document.body) {
            loadingElement.className = 'absolute inset-0 bg-white bg-opacity-90 flex items-center justify-center z-10';
            target.style.position = 'relative';
            target.appendChild(loadingElement);
        } else {
            document.body.appendChild(loadingElement);
        }

        this.loadingStates.set(key, {
            element: loadingElement,
            message: message,
            target: target
        });
    }

    /**
     * 隐藏Loading状态
     * @param {string} key - Loading状态的唯一标识
     */
    hideLoading(key) {
        const loadingState = this.loadingStates.get(key);
        if (!loadingState) return;

        const { element, target } = loadingState;
        element.remove();
        this.loadingStates.delete(key);
    }

    /**
     * 更新Loading消息
     * @param {string} key - Loading状态的唯一标识
     * @param {string} message - 新的Loading消息
     */
    updateLoadingMessage(key, message) {
        const loadingState = this.loadingStates.get(key);
        if (!loadingState) return;

        const messageElement = loadingState.element.querySelector('p');
        if (messageElement) {
            messageElement.textContent = message;
        }
        loadingState.message = message;
    }

    /**
     * 显示确认对话框
     * @param {Object} options - 配置选项
     * @returns {Promise<boolean>} - 用户确认结果
     */
    showConfirm(options = {}) {
        return new Promise((resolve) => {
            const {
                title = '确认操作',
                message = '确定要执行此操作吗？',
                confirmText = '确定',
                cancelText = '取消',
                confirmClass = 'bg-red-600 hover:bg-red-700',
                onConfirm = null,
                onCancel = null
            } = options;

            const titleElement = this.confirmDialog.querySelector('#confirm-title');
            const messageElement = this.confirmDialog.querySelector('#confirm-message');
            const confirmButton = this.confirmDialog.querySelector('#confirm-ok');
            const cancelButton = this.confirmDialog.querySelector('#confirm-cancel');

            titleElement.textContent = title;
            messageElement.textContent = message;
            confirmButton.textContent = confirmText;
            cancelButton.textContent = cancelText;
            confirmButton.className = `px-4 py-2 text-white rounded transition-colors ${confirmClass}`;

            const handleConfirm = () => {
                this.hideConfirm();
                if (onConfirm) onConfirm();
                resolve(true);
            };

            const handleCancel = () => {
                this.hideConfirm();
                if (onCancel) onCancel();
                resolve(false);
            };

            confirmButton.onclick = handleConfirm;
            cancelButton.onclick = handleCancel;

            // ESC键取消
            const handleEsc = (e) => {
                if (e.key === 'Escape') {
                    handleCancel();
                    document.removeEventListener('keydown', handleEsc);
                }
            };
            document.addEventListener('keydown', handleEsc);

            // 点击背景取消
            this.confirmDialog.onclick = (e) => {
                if (e.target === this.confirmDialog) {
                    handleCancel();
                }
            };

            this.confirmDialog.classList.remove('hidden');
            this.confirmDialog.classList.add('flex');
        });
    }

    /**
     * 隐藏确认对话框
     */
    hideConfirm() {
        this.confirmDialog.classList.add('hidden');
        this.confirmDialog.classList.remove('flex');
    }

    /**
     * 显示模态框
     * @param {string|HTMLElement} content - 模态框内容
     * @param {Object} options - 配置选项
     */
    showModal(content, options = {}) {
        const {
            title = '',
            size = 'md',
            closable = true,
            onClose = null
        } = options;

        const sizeClasses = {
            sm: 'max-w-md',
            md: 'max-w-lg',
            lg: 'max-w-2xl',
            xl: 'max-w-4xl',
            full: 'max-w-full mx-4'
        };

        const modal = document.createElement('div');
        modal.className = 'bg-white rounded-lg shadow-xl w-full ' + sizeClasses[size];
        
        let headerHTML = '';
        if (title || closable) {
            headerHTML = `
                <div class="flex items-center justify-between p-6 border-b">
                    <h3 class="text-lg font-semibold">${title}</h3>
                    ${closable ? '<button class="text-gray-400 hover:text-gray-600" onclick="window.uxUtils.closeModal(this.closest(\'.modal-wrapper\'))">×</button>' : ''}
                </div>
            `;
        }

        modal.innerHTML = `
            ${headerHTML}
            <div class="p-6">
                ${typeof content === 'string' ? content : content.outerHTML}
            </div>
        `;

        const wrapper = document.createElement('div');
        wrapper.className = 'modal-wrapper fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4';
        wrapper.appendChild(modal);

        // 点击背景关闭
        if (closable) {
            wrapper.onclick = (e) => {
                if (e.target === wrapper) {
                    this.closeModal(wrapper);
                }
            };
        }

        this.modalContainer.appendChild(wrapper);

        // ESC键关闭
        const handleEsc = (e) => {
            if (e.key === 'Escape' && closable) {
                this.closeModal(wrapper);
                document.removeEventListener('keydown', handleEsc);
            }
        };
        document.addEventListener('keydown', handleEsc);

        // 存储关闭回调
        wrapper._onClose = onClose;
    }

    /**
     * 关闭模态框
     * @param {HTMLElement} modal - 模态框元素
     */
    closeModal(modal) {
        if (modal._onClose) {
            modal._onClose();
        }
        modal.remove();
    }

    /**
     * 显示表单验证错误
     * @param {HTMLFormElement} form - 表单元素
     * @param {Object} errors - 错误对象 {field: message}
     */
    showFormErrors(form, errors) {
        // 清除之前的错误
        this.clearFormErrors(form);

        Object.entries(errors).forEach(([field, message]) => {
            const input = form.querySelector(`[name="${field}"]`);
            if (input) {
                input.classList.add('border-red-500');
                
                const errorElement = document.createElement('p');
                errorElement.className = 'text-red-500 text-sm mt-1';
                errorElement.textContent = message;
                input.parentNode.appendChild(errorElement);
            }
        });

        // 滚动到第一个错误
        const firstError = form.querySelector('.border-red-500');
        if (firstError) {
            firstError.scrollIntoView({ behavior: 'smooth', block: 'center' });
            firstError.focus();
        }
    }

    /**
     * 清除表单验证错误
     * @param {HTMLFormElement} form - 表单元素
     */
    clearFormErrors(form) {
        form.querySelectorAll('.border-red-500').forEach(input => {
            input.classList.remove('border-red-500');
        });
        
        form.querySelectorAll('.text-red-500').forEach(error => {
            error.remove();
        });
    }

    /**
     * 设置全局错误处理
     */
    setupGlobalErrorHandling() {
        window.addEventListener('error', (event) => {
            console.error('Global error:', event.error);
            this.showError('页面发生错误，请刷新重试');
        });

        window.addEventListener('unhandledrejection', (event) => {
            console.error('Unhandled promise rejection:', event.reason);
            this.showError('网络请求失败，请检查网络连接');
        });
    }

    /**
     * 设置Ajax拦截器
     */
    setupAjaxInterceptors() {
        // Fetch拦截器
        const originalFetch = window.fetch;
        window.fetch = async (...args) => {
            const url = args[0];
            const options = args[1] || {};
            
            // 显示loading
            const loadingKey = `fetch-${url}-${Date.now()}`;
            if (!options.noLoading) {
                this.showLoading(loadingKey);
            }

            try {
                const response = await originalFetch(...args);
                
                // 处理错误响应
                if (!response.ok) {
                    const errorData = await response.json().catch(() => ({}));
                    const errorMessage = errorData.message || `请求失败 (${response.status})`;
                    this.showError(errorMessage);
                }
                
                return response;
            } catch (error) {
                this.showError('网络请求失败，请检查网络连接');
                throw error;
            } finally {
                this.hideLoading(loadingKey);
            }
        };

        // XMLHttpRequest拦截器
        const originalXHROpen = XMLHttpRequest.prototype.open;
        const originalXHRSend = XMLHttpRequest.prototype.send;

        XMLHttpRequest.prototype.open = function(...args) {
            this._url = args[1];
            return originalXHROpen.apply(this, args);
        };

        XMLHttpRequest.prototype.send = function(...args) {
            const loadingKey = `xhr-${this._url}-${Date.now()}`;
            
            if (!this.noLoading) {
                window.uxUtils.showLoading(loadingKey);
            }

            this.addEventListener('loadend', () => {
                window.uxUtils.hideLoading(loadingKey);
                
                if (this.status >= 400) {
                    try {
                        const errorData = JSON.parse(this.responseText);
                        const errorMessage = errorData.message || `请求失败 (${this.status})`;
                        window.uxUtils.showError(errorMessage);
                    } catch {
                        window.uxUtils.showError(`请求失败 (${this.status})`);
                    }
                }
            });

            return originalXHRSend.apply(this, args);
        };
    }

    /**
     * 防抖函数
     * @param {Function} func - 要防抖的函数
     * @param {number} wait - 等待时间（毫秒）
     */
    debounce(func, wait) {
        let timeout;
        return function executedFunction(...args) {
            const later = () => {
                clearTimeout(timeout);
                func(...args);
            };
            clearTimeout(timeout);
            timeout = setTimeout(later, wait);
        };
    }

    /**
     * 节流函数
     * @param {Function} func - 要节流的函数
     * @param {number} limit - 时间限制（毫秒）
     */
    throttle(func, limit) {
        let inThrottle;
        return function() {
            const args = arguments;
            const context = this;
            if (!inThrottle) {
                func.apply(context, args);
                inThrottle = true;
                setTimeout(() => inThrottle = false, limit);
            }
        };
    }

    /**
     * 复制到剪贴板
     * @param {string} text - 要复制的文本
     */
    async copyToClipboard(text) {
        try {
            await navigator.clipboard.writeText(text);
            this.showSuccess('已复制到剪贴板');
        } catch (err) {
            // 降级处理
            const textArea = document.createElement('textarea');
            textArea.value = text;
            document.body.appendChild(textArea);
            textArea.select();
            document.execCommand('copy');
            document.body.removeChild(textArea);
            this.showSuccess('已复制到剪贴板');
        }
    }

    /**
     * 格式化文件大小
     * @param {number} bytes - 字节数
     */
    formatFileSize(bytes) {
        if (bytes === 0) return '0 Bytes';
        const k = 1024;
        const sizes = ['Bytes', 'KB', 'MB', 'GB'];
        const i = Math.floor(Math.log(bytes) / Math.log(k));
        return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
    }

    /**
     * 格式化日期时间
     * @param {string|Date} date - 日期
     * @param {string} format - 格式化模板
     */
    formatDateTime(date, format = 'YYYY-MM-DD HH:mm:ss') {
        const d = new Date(date);
        const year = d.getFullYear();
        const month = String(d.getMonth() + 1).padStart(2, '0');
        const day = String(d.getDate()).padStart(2, '0');
        const hours = String(d.getHours()).padStart(2, '0');
        const minutes = String(d.getMinutes()).padStart(2, '0');
        const seconds = String(d.getSeconds()).padStart(2, '0');

        return format
            .replace('YYYY', year)
            .replace('MM', month)
            .replace('DD', day)
            .replace('HH', hours)
            .replace('mm', minutes)
            .replace('ss', seconds);
    }
}

// 创建全局实例
window.uxUtils = new UXUtils();

// 导出模块（如果支持ES6模块）
if (typeof module !== 'undefined' && module.exports) {
    module.exports = UXUtils;
}